package com.victor9ac.tfm.rome2rio.api.adapter.parse;

import java.text.Normalizer;

import org.jdom.Document;
import org.jdom.Element;

import com.victor9ac.mashup.api.travel.Agency;
import com.victor9ac.mashup.api.travel.Airline;
import com.victor9ac.mashup.api.travel.Airport;
import com.victor9ac.mashup.api.travel.Stop;
import com.victor9ac.mashup.api.travel.Travel;
import com.victor9ac.mashup.api.travel.TravelRoute;

public class Rome2RioSearchParse {

	private static final int MAXIMUM_ROUTES = 5;
	private static final int MAXIMUM_AIRLINES = 3;
	private static final int MAXIMUM_AGENCIES = 3;

	public Travel parseResponse(Document doc,String origin, String destination) {

		String d = destination.trim();
		d = d.toLowerCase();

		Travel travel = new Travel();
		travel.setFrom(origin);
		travel.setTo(destination);
		
		Element root = doc.getRootElement();

		for (Object o : root.getChildren()) {
			Element elem = (Element) o;

			airportBuilder(travel, elem);

			airlineBuilder(travel, elem);

			agenciesBuilder(travel, elem);

			routesBuilder(travel, elem);

		}

		return travel;
	}

	private void routesBuilder(Travel travel, Element elem) {
		String tagName = elem.getName();
		if ("Route".equals(tagName)) {
			if (travel.getTravelRoutes().size() < MAXIMUM_ROUTES) {
				String name = stripAccentsAndLowerCase(elem
						.getAttributeValue("name"));
				String distance = stripAccentsAndLowerCase(elem
						.getAttributeValue("distance"));
				String duration = stripAccentsAndLowerCase(elem
						.getAttributeValue("duration"));
				String transferDuration = stripAccentsAndLowerCase(elem
						.getAttributeValue("totalTransferDuration"));

				TravelRoute route = new TravelRoute(name, distance, duration,
						transferDuration);

				routeFeaturesBuilder(elem, route);

				travel.getTravelRoutes().add(route);

			}
		}
	}

	private void routeFeaturesBuilder(Element elem, TravelRoute route) {
		for (Object oRoute : elem.getChildren()) {
			Element elemRoute = (Element) oRoute;
			String tagRouteName = elemRoute.getName();

			if ("IndicativePrice".equals(tagRouteName)) {
				route.setPriceRoute(stripAccentsAndLowerCase(elemRoute
						.getAttributeValue("price")));
			}
			if ("Stop".equals(tagRouteName)) {
				Stop stop = new Stop(
						stripAccentsAndLowerCase(elemRoute.getAttributeValue("name")),
						stripAccentsAndLowerCase(elemRoute.getAttributeValue("kind")));
				route.getStops().add(stop);
			}
		}
	}

	private void airlineBuilder(Travel travel, Element elem) {
		String tagName = elem.getName();
		if ("Airline".equals(tagName)) {
			if (travel.getAirlines().size() < MAXIMUM_AIRLINES) {
				Airline airline = new Airline(
						stripAccentsAndLowerCase(elem.getAttributeValue("name")),
						stripAccentsAndLowerCase(elem.getAttributeValue("url")),
						stripAccentsAndLowerCase(elem
								.getAttributeValue("iconPath")));
				travel.getAirlines().add(airline);
			}
		}
	}

	private void agenciesBuilder(Travel travel, Element elem) {
		String tagName = elem.getName();
		if ("Agency".equals(tagName)) {
			if (travel.getAgencies().size() < MAXIMUM_AGENCIES) {
				Agency agency = new Agency(attributeValue(elem, "name"),
						attributeValue(elem, "url"), attributeValue(elem,
								"iconPath"));
				travel.getAgencies().add(agency);
			}
		}
	}

	private void airportBuilder(Travel travel, Element elem) {
		String tagName = elem.getName();
		if ("Airport".equals(tagName)) {
			String airportName = stripAccentsAndLowerCase(elem
					.getAttributeValue("name"));
			if (travel.getFrom().equalsIgnoreCase(airportName)) {
				Airport airportFrom = buildAirport(travel, elem, airportName);
				travel.setAirportTo(airportFrom);

			} else if (travel.getTo().equalsIgnoreCase(airportName)) {
				Airport airportTo = buildAirport(travel, elem, airportName);
				travel.setAirportTo(airportTo);
			}
		}
	}

	private Airport buildAirport(Travel travel, Element elem, String airportName) {
		return new Airport(attributeValue(elem, "code"), airportName,
				attributeValue(elem, "countryCode"), attributeValue(elem,
						"timeZone"));
	}

	private String attributeValue(Element elem, String code) {
		return stripAccentsAndLowerCase(elem.getAttributeValue(code));
	}

	@Deprecated
	private void placeBuilder(String destinationRequested, Travel travel,
			Element elem) {
		String tagName = elem.getName();
		if ("Place".equals(tagName)) {
			String placeName = stripAccentsAndLowerCase(elem
					.getAttributeValue("name"));
			if (destinationRequested.equalsIgnoreCase(placeName)) {
				travel.setTo(destinationRequested);
			} else {
				travel.setFrom(placeName);
			}
		}
	}

	public String stripAccentsAndLowerCase(String strToStrip) {

		String res = null;

		if (strToStrip != null) {
			strToStrip = strToStrip.trim();
			String strStripped = null;
			// Normalizamos en la forma NFD (Canonical decomposition)
			strToStrip = Normalizer.normalize(strToStrip, Normalizer.Form.NFD);
			// Reemplazamos los acentos con una una expresión regular de Bloque
			// Unicode
			strStripped = strToStrip.replaceAll(
					"\\p{InCombiningDiacriticalMarks}+", "");
			res = strStripped.toLowerCase();

		}
		return res;

	}

}
